package com.mask.im.business.aspect;

import com.alibaba.fastjson.JSON;
import com.mask.im.business.annotation.OptLog;
import com.mask.im.business.common.util.IpUtil;
import com.mask.im.business.common.util.MaskIMSecurityUtils;
import com.mask.im.business.mapper.OperationLogMapper;
import com.mask.im.business.model.entity.SysOperationLogEntity;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.log4j.Log4j2;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Optional;

/**
 * 操作日志切面
 * 
 * @author jian
 */
@Log4j2
@Aspect
@Component
public class OperationLogAspect {

    @Resource
    private OperationLogMapper operationLogMapper;

    @Pointcut("@annotation(com.mask.im.business.annotation.OptLog)")
    public void operationLogPointCut() {
    }

    @AfterReturning(value = "operationLogPointCut()", returning = "result")
    public void saveOperationLog(JoinPoint joinPoint, Object result) {
        try {
            // 异步保存日志，避免影响主业务
            saveOperationLogAsync(joinPoint, result);
        } catch (Exception e) {
            log.error("操作日志切面处理异常", e);
        }
    }

    @Async
    public void saveOperationLogAsync(JoinPoint joinPoint, Object result) {
        try {
            // 获取请求信息
            RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
            if (requestAttributes == null) {
                log.warn("无法获取请求上下文，跳过操作日志记录");
                return;
            }

            HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
            if (request == null) {
                log.warn("无法获取HttpServletRequest，跳过操作日志记录");
                return;
            }

            // 构建操作日志实体
            SysOperationLogEntity logEntity = buildOperationLog(joinPoint, result, request);
            
            // 保存到数据库
            operationLogMapper.insert(logEntity);
            
            log.debug("操作日志保存成功，用户: {}, 操作: {}", logEntity.getNickname(), logEntity.getOptDesc());

        } catch (Exception e) {
            log.error("保存操作日志失败", e);
        }
    }

    /**
     * 构建操作日志实体
     */
    private SysOperationLogEntity buildOperationLog(JoinPoint joinPoint, Object result, HttpServletRequest request) {
        SysOperationLogEntity logEntity = new SysOperationLogEntity();
        
        try {
            // 获取方法信息
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            
            // 获取目标类（解决代理问题）
            Class<?> targetClass = joinPoint.getTarget().getClass();
            
            // 获取注解信息 - 修复后的方式
            Api api = getApiAnnotation(targetClass);
            ApiOperation apiOperation = getApiOperationAnnotation(method, targetClass);
            OptLog optLog = getOptLogAnnotation(method, targetClass);
            
            // 设置模块信息
            if (api != null && api.tags().length > 0) {
                logEntity.setOptModule(api.tags()[0]);
            } else {
                logEntity.setOptModule("未知模块");
            }
            
            // 设置操作类型和描述
            if (optLog != null) {
                logEntity.setOptType(optLog.optType());
            } else {
                logEntity.setOptType("未知操作");
            }
            
            if (apiOperation != null) {
                logEntity.setOptDesc(apiOperation.value());
            } else {
                logEntity.setOptDesc(method.getName());
            }
            
            // 设置方法信息
            String className = targetClass.getName();
            String methodName = method.getName();
            logEntity.setOptMethod(className + "." + methodName);
            
            // 设置请求信息
            logEntity.setRequestMethod(request.getMethod());
            logEntity.setOptUri(request.getRequestURI());
            
            // 设置请求参数
            if (joinPoint.getArgs().length > 0) {
                if (joinPoint.getArgs()[0] instanceof MultipartFile) {
                    logEntity.setRequestParam("file");
                } else {
                    logEntity.setRequestParam(JSON.toJSONString(joinPoint.getArgs()));
                }
            }
            
            // 设置响应数据
            if (result != null) {
                logEntity.setResponseData(JSON.toJSONString(result));
            }
            
            // 设置用户信息
            try {
                Integer userId = MaskIMSecurityUtils.getUserId();
//                String nickname = MaskIMSecurityUtils.getUserDetailsDTO().getNickName();
                String nickname = "MaskIMSecurityUtils.getUserDetailsDTO().getNickName()";

                logEntity.setUserId(Optional.ofNullable(userId).orElse(0));
                logEntity.setNickname(Optional.ofNullable(nickname).orElse("anonymous"));
            } catch (Exception e) {
                logEntity.setUserId(0);
                logEntity.setNickname("anonymous");
            }
            
            // 设置IP信息
            String ipAddress = IpUtil.getIpAddress(request);
            logEntity.setIpAddress(ipAddress);
            logEntity.setIpSource(IpUtil.getIpSource(ipAddress));
            
            // 设置时间
            logEntity.setCreateTime(LocalDateTime.now());
            
        } catch (Exception e) {
            log.error("构建操作日志实体失败", e);
        }
        
        return logEntity;
    }
    
    /**
     * 获取Api注解 - 处理代理问题
     */
    private Api getApiAnnotation(Class<?> targetClass) {
        try {
            // 先尝试从目标类获取
            Api api = targetClass.getAnnotation(Api.class);
            if (api != null) {
                return api;
            }
            
            // 如果目标类没有，尝试从接口获取
            Class<?>[] interfaces = targetClass.getInterfaces();
            for (Class<?> interfaceClass : interfaces) {
                api = interfaceClass.getAnnotation(Api.class);
                if (api != null) {
                    return api;
                }
            }
            
            // 如果接口也没有，尝试从父类获取
            Class<?> superClass = targetClass.getSuperclass();
            if (superClass != null && !superClass.equals(Object.class)) {
                api = superClass.getAnnotation(Api.class);
                if (api != null) {
                    return api;
                }
            }
            
        } catch (Exception e) {
            log.warn("获取Api注解失败: {}", targetClass.getName(), e);
        }
        
        return null;
    }
    
    /**
     * 获取ApiOperation注解 - 处理代理问题
     */
    private ApiOperation getApiOperationAnnotation(Method method, Class<?> targetClass) {
        try {
            // 先尝试从方法获取
            ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
            if (apiOperation != null) {
                return apiOperation;
            }
            
            // 如果方法没有，尝试从目标类的方法获取
            Method targetMethod = targetClass.getMethod(method.getName(), method.getParameterTypes());
            apiOperation = targetMethod.getAnnotation(ApiOperation.class);
            if (apiOperation != null) {
                return apiOperation;
            }
            
            // 如果目标类也没有，尝试从接口获取
            Class<?>[] interfaces = targetClass.getInterfaces();
            for (Class<?> interfaceClass : interfaces) {
                try {
                    Method interfaceMethod = interfaceClass.getMethod(method.getName(), method.getParameterTypes());
                    apiOperation = interfaceMethod.getAnnotation(ApiOperation.class);
                    if (apiOperation != null) {
                        return apiOperation;
                    }
                } catch (NoSuchMethodException ignored) {
                    // 接口可能没有这个方法，继续尝试下一个
                }
            }
            
        } catch (Exception e) {
            log.warn("获取ApiOperation注解失败: {}.{}", targetClass.getName(), method.getName(), e);
        }
        
        return null;
    }
    
    /**
     * 获取OptLog注解 - 处理代理问题
     */
    private OptLog getOptLogAnnotation(Method method, Class<?> targetClass) {
        try {
            // 先尝试从方法获取
            OptLog optLog = method.getAnnotation(OptLog.class);
            if (optLog != null) {
                return optLog;
            }
            
            // 如果方法没有，尝试从目标类的方法获取
            Method targetMethod = targetClass.getMethod(method.getName(), method.getParameterTypes());
            optLog = targetMethod.getAnnotation(OptLog.class);
            if (optLog != null) {
                return optLog;
            }
            
            // 如果目标类也没有，尝试从接口获取
            Class<?>[] interfaces = targetClass.getInterfaces();
            for (Class<?> interfaceClass : interfaces) {
                try {
                    Method interfaceMethod = interfaceClass.getMethod(method.getName(), method.getParameterTypes());
                    optLog = interfaceMethod.getAnnotation(OptLog.class);
                    if (optLog != null) {
                        return optLog;
                    }
                } catch (NoSuchMethodException ignored) {
                    // 接口可能没有这个方法，继续尝试下一个
                }
            }
            
        } catch (Exception e) {
            log.warn("获取OptLog注解失败: {}.{}", targetClass.getName(), method.getName(), e);
        }
        
        return null;
    }
}